#ifndef __MY_DATAMANAGER__
#define __MY_DATAMANAGER__

#include "Util.hpp"
#include "Config.hpp"
#include <unordered_map>

namespace hhbcloud
{
    struct Backinfo // 定义并获取文件存在在服务器上的备份信息
    {
        bool NewBackinfo(const std::string& realpath)
        {
            FileUtil fu(realpath);
            if (fu.Exists() == false) // 文件不存在则报错返回
            {
                std::cout << "newBackinfo file is not exists" << std::endl;
                return false;
            }

            _pack_flag = false;

            _fsize = fu.FileSize();
            _atime = fu.LastATime();
            _mtime = fu.LastMTime();
            _real_path = realpath;

            // config获取配置文件中定义的单例类 
            Config* config = Config::GetInstance();

            // 压缩路径应该是 配置文件中的压缩目录 + 文件名称 + 文件压缩后缀
            _pack_path = config->GetPackDir() + fu.FileName() + config->GetPackfileSuffix();

            // url下载路径应该是 配置文件中下载前缀 + 文件名称
            std::string downloadPrefix = config->GetDownloadPrefix();
            std::string urlpath = downloadPrefix + fu.FileName();
            _url_path = urlpath;

            return true;
        }

        bool _pack_flag; // 文件是否被压缩标志
        size_t _fsize; // 文件的大小
        time_t _atime; // 文件最后一次访问时间
        time_t _mtime; // 文件最后一次修改时间
        std::string _real_path; // 文件实际存储路径名称
        std::string _pack_path; // 亚搜包存储路径名称
        std::string _url_path; // url下载文件的路径
    };

    class DataManager
    {
    public:
        DataManager()
        {
            // _backup_file 持久化存储文件，就是配置文件中的文件备份信息的文件
            // 对数据的管理本质就是对服务器备份的文件信息的管理，在进行操作时，需要将当前所有文件信息加载到内存中
            // 这里用哈希表来存储，提高效率

            _backup_file = Config::GetInstance()->GetBackupFile(); // 通过config单例类获取
            // 初始化读写锁
            pthread_rwlock_init(&_rwlock, nullptr);

            // 创建对象的同时，初始化加载所有备份信息数据
            InitLoad();
        }

        // 初始化加载 每次创建类都需要先初始化加载所有的数据
        bool InitLoad()
        {
            FileUtil fu(_backup_file);
            if (fu.Exists() == false)
            {
                std::cout << "DataManager InitLoad file is not exists" << std::endl;
                return false;
            }

            // 获取备份信息文件中的所有备份信息
            std::string body;
            fu.GetContent(&body);

            // 反序列化
            Json::Value root;
            JsonUtil::Deserialization(body, &root);

            // 通过反序列化得到的json结构体，构建备份信息，插入到哈希表中
            for (int i = 0;i < root.size(); i++)
            {
                Backinfo backinfo;
                backinfo._pack_flag = root[i]["pack_flag"].asBool();
                backinfo._fsize = root[i]["fsize"].asInt();
                backinfo._atime = root[i]["atime"].asInt();
                backinfo._mtime = root[i]["mtime"].asInt();
                backinfo._real_path = root[i]["real_path"].asString();
                backinfo._pack_path = root[i]["pack_path"].asString();
                backinfo._url_path = root[i]["url_path"].asString();

                // 获取的一个文件备份信息插入到哈希表中
                Insert(backinfo);
            }

            return true;
        }

        // 新增数据
        bool Insert(const Backinfo& backinfo)
        {
            // 读写锁，在写入时，将写进行加锁，读不加锁，一次只能有一个线程在执行写操作
            pthread_rwlock_wrlock(&_rwlock);

            // 所有数据都已经加载到哈希表中了，所以此时只需要操作哈希表即可
            // 在哈希表中我们以备份文件信息中的url路径和文件备份信息构成键值对
            _table[backinfo._url_path] = backinfo;
            pthread_rwlock_unlock(&_rwlock);

            // 每插入一个数据都要持久化存储
            Storage();
            return true;
        }

        // 更新数据
        bool Update(const Backinfo& backinfo)
        {
            pthread_rwlock_wrlock(&_rwlock);

            _table[backinfo._url_path] = backinfo; // key值相同，会默认覆盖之前的值
            pthread_rwlock_unlock(&_rwlock);

            // 每更新一个数据都要持久化存储
            Storage();
            return true;
        }

        // 查询数据 通过url获取单个文件的备份信息
        // 当是下载请求时，我们需要获取单个文件的信息，但是如果是页面展示请求，则需要获取多个文件的信息
        bool GetOneByUrl(const std::string& url, Backinfo* backinfo)
        {
            pthread_rwlock_wrlock(&_rwlock);

            auto it = _table.find(url);

            if (it == _table.end())
            {
                std::cout << "GetOneByUrl is not find" << std::endl;
                pthread_rwlock_unlock(&_rwlock);
                return false;
            }
            pthread_rwlock_unlock(&_rwlock);
            *backinfo = it->second;
            return true;
        }

        // 通过文件真是路径来获取文件备份信息 通过真实路径查询在备份信息文件中是否有当前文件，判断文件是否被备份
        bool GetOneByRealpath(const std::string& realpath, Backinfo* backinfo)
        {
            pthread_rwlock_wrlock(&_rwlock);
            auto it = _table.begin();
            for (; it != _table.end(); ++it)
            {
                if (it->second._real_path == realpath)
                {
                    *backinfo = it->second;
                    pthread_rwlock_unlock(&_rwlock);
                    return true;
                }
            }

            pthread_rwlock_unlock(&_rwlock);
            return false;
        }

        // 获取所有备份文件的信息  用于展示请求
        bool GetAll(std::vector<Backinfo>* array)
        {
            pthread_rwlock_wrlock(&_rwlock);

            auto it = _table.begin();
            for (;it != _table.end(); ++it)
            {
                array->push_back(it->second);
            }
            pthread_rwlock_unlock(&_rwlock);
            return true;
        }

        // 持久化存储，也就是将已经操作的（插入或修改）加载到内存中的哈希表中的数据写入到备份信息的文件中
        bool Storage()
        {
            // 创建一个备份文件信息的数据
            std::vector<Backinfo> array;
            // 获取所有的备份信息到数组中
            GetAll(&array);
            // 先将所有的备份信息，存储到json数组中，然后通过序列化， 最后统一写入文件
            Json::Value root;
            for (int i = 0;i < array.size(); i++)
            {
                Json::Value item; // 构建好每一个备份文件信息
                item["pack_flag"] = array[i]._pack_flag;
                item["fsize"] = (Json::Int64)array[i]._fsize;
                item["atime"] = (Json::Int64)array[i]._atime;
                item["mtime"] = (Json::Int64)array[i]._mtime;
                item["real_path"] = array[i]._real_path;
                item["pack_path"] = array[i]._pack_path;
                item["url_path"] = array[i]._url_path;

                root.append(item); // 构建好备份文件信息后，写入json数组中
            }

            // 序列化
            std::string body;
            JsonUtil::Serialization(root, &body);
            // 此时root被序列化为一个字符串，放入body中
            FileUtil fu(_backup_file);

            if (fu.SetContent(body) == false) // 若文件不存在fu.setContent中的ofstream流在打开文件时，会自动创建
            {
                std::cout << "DataManager storage set file content error" << std::endl;
                return false;
            }

            return true;
        }



        ~DataManager()
        {
            // 析构时，销毁读写锁
            pthread_rwlock_destroy(&_rwlock);
        }
    private:
        std::string _backup_file; // 持久化存储的文件，也就是配置文件中 备份文件信息的文件
        pthread_rwlock_t _rwlock; // 读写锁， -- 读共享，写互斥
        std::unordered_map<std::string, Backinfo> _table; // 一个哈希表，用来高效管理数据
    };
}



#endif